#include "ebm_env.h"

#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>

#if 0
#define rtp_dbg(...)
#else
#define rtp_dbg printf
#endif
#define __PACKED__        __attribute__ ((__packed__)) 

static unsigned short rtp_wcnt=0;
static volatile unsigned int rtp_pack_wcnt=0;
static volatile unsigned int rtp_pack_loss=0;

struct rsockt{
#define _FD_INVALID 0    
	int fd;
	unsigned int lastTimeSec;
	unsigned int sndDtaCnt;
	unsigned int speedCnt;
	unsigned int speed;
	volatile unsigned int ipaddr;
	volatile unsigned short port;
	unsigned char keepSec;
	volatile unsigned char isNeedCreat;
};

struct _RTP_FIXED_HEADER
{
  
    unsigned char csrc_len:4;        /**//* expect 0 */
	unsigned char extension:1;        /**//* expect 1, see RTP_OP below */
	unsigned char padding:1;        /**//* expect 0 */
	unsigned char version:2;        /**//* expect 2 */
	
    /**//* byte 0 */
    /**//* bytes 2, 3 */
    /**//* byte 1 */
    
    unsigned char payload:7;        /**//* RTP_PAYLOAD_RTSP */
	unsigned char marker:1;        /**//* expect 1 */
	
    unsigned short seq_no;            
    /**//* bytes 4-7 */
    unsigned int timestamp;        
    /**//* bytes 8-11 */
    unsigned int ssrc;            /**//* stream number is used here. */
} __PACKED__;

typedef struct _RTP_FIXED_HEADER RTP_FIXED_HEADER;


void _getLocalIpAddr(in_addr_t *addr, char* ifa_name)
{
    struct ifaddrs *ifAddrStruct = NULL;
    getifaddrs(&ifAddrStruct);
    while (ifAddrStruct != NULL)
    {
       if (ifAddrStruct->ifa_addr->sa_family == AF_INET)
       {
           if (strcmp(ifa_name,ifAddrStruct->ifa_name) == 0)
           {
               memcpy(addr, &(((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr.s_addr), sizeof(in_addr_t));
           }
       }
       ifAddrStruct = ifAddrStruct->ifa_next;
    }
    return;
}

#define IS_MULTICAST(a)    ((((unsigned long)(a)) & 0x000000F0) == 0x000000E0)

static volatile unsigned short port;
static volatile unsigned int ipaddr;
static struct rsockt rtp_net_handle = {_FD_INVALID,0,0};

static void _socket_close(int *fd)
{
	if(*fd != _FD_INVALID){
		close(*fd);
		*fd = _FD_INVALID;
	}
}

static int rtp_socket_open_unicast(unsigned int server_ip, unsigned short server_port)
{
	int conn_sock;
	struct sockaddr_in server_addr;
	
	conn_sock	= socket(AF_INET, SOCK_DGRAM, 0);
	if (conn_sock < 0) {
		perror("socket(2) error");
		return _FD_INVALID;	
	}

	(void)memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family		= AF_INET;
	server_addr.sin_port		= htons(server_port);
	
	if (bind(conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
		perror("bind(2) error");
		goto release;
	}
	
#if 1	
	/*test "0" byte */
	server_addr.sin_addr.s_addr	= htonl(server_ip);
	if (sendto(conn_sock, "0", 0 , 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("send data error");
        goto release;
    }
#endif	

	return conn_sock;
release:
	close(conn_sock);
	return _FD_INVALID;	
}

static int rtp_socket_open_multicast(unsigned int macst_ip, unsigned short mcast_port)
{
	int conn_sock, err = -1;
	struct sockaddr_in local_addr;
	struct ip_mreq mreq;
	conn_sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (conn_sock == -1)
	{
		printf("pg socket err\n");
		return _FD_INVALID;
	}
	memset(&local_addr, 0, sizeof(local_addr));
	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	local_addr.sin_port = htons(mcast_port);
	err = bind(conn_sock,(struct sockaddr*)&local_addr, sizeof(local_addr)) ;
	if(err < 0)
	{
		printf("pg bind err\n");
		goto release;
	}
	mreq.imr_multiaddr.s_addr = htonl(macst_ip);
#if 1	/*嵌入式*/
#define PLAT_NET_IF_NAME "eth0"
	_getLocalIpAddr(&(mreq.imr_interface.s_addr), PLAT_NET_IF_NAME);
	printf("local ip=%x\n", mreq.imr_interface.s_addr);
#else
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
#endif
	setsockopt(conn_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
	
	err = setsockopt(conn_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq));
	if (err < 0)
	{
		printf("pg add multiaddr err\n");
		goto release;;
	}
	return conn_sock;
release:
	close(conn_sock);
	return _FD_INVALID;
}


static unsigned char rtp_creat_connect_socket(struct rsockt *h_net)
{
	int fd=0;
	unsigned int ip;
	unsigned short port;
	unsigned char ret = 0;
	_socket_close(&h_net->fd);


	ip = h_net->ipaddr;
	port = h_net->port;	
	
	if(ip > 0 && port > 0 ){
		unsigned int tmpip= htonl(ip);
		
		if(IS_MULTICAST(tmpip)){
			ebmdbg_command("it's a muliticast ipaddr: %x:%d\n", ip, port);
			fd = rtp_socket_open_multicast(ip, port);
		}
		else{
			ebmdbg_command("it's a unicast ipaddr: %x:%d\n", ip, port);
			fd = rtp_socket_open_unicast(ip, port);
		}
		if(fd  != _FD_INVALID ){
			rtp_wcnt=0;
			h_net->fd = fd;
			h_net->lastTimeSec = 0;
			h_net->keepSec = 0;
			h_net->speedCnt = 0;
			ret = 1;	
		}
	}	
	return ret;
}


static unsigned char rtp_block_rec(unsigned int fd)
{
	unsigned char ret=0;
	static unsigned char rbuf[1460];
	int	nsel;
	struct	timeval timeover={0};
	fd_set rfd_set; 
	timeover.tv_sec = 0;
	timeover.tv_usec = 1000;
	FD_ZERO( &rfd_set );
	FD_SET(fd, &rfd_set );
	nsel = select( fd+1, &rfd_set, NULL, NULL, &timeover );
	if ( nsel > 0 )
	{
		if(FD_ISSET( fd, &rfd_set )){

			memset(rbuf, 0 , 20);
		
			int rlen = read(fd, rbuf, 1460);
			if(rlen < 0){
				printf("rtp socket unvaild\n");
				rtp_net_stop();
			}
			else if(rlen == 0){
				//rtp_net_restart();
			}
			else{

#if 1
				static unsigned short last_sn=0;
				unsigned short new_sn;
				new_sn= (rbuf[2] << 8) | rbuf[3];
				
				if(rlen == 400){
					ebm_plat_mp3_play(&rbuf[16], rlen-16);	
					if(new_sn != last_sn+1 && last_sn!=0){
						rtp_pack_wcnt+= rlen;
						ebmdbg_command("! sn= %03d / %03d\n", new_sn, last_sn);
					}
					last_sn= new_sn;
				}
			rtp_net_handle.speedCnt+= rlen;
#else	
		unsigned short new_sn;
		new_sn= (rbuf[2] << 8) | rbuf[3];
		rtp_dbg("l%04d, sn:%d\n", rlen, new_sn);
#endif
			ret=1;	
			}
				
		}
	}			
	return ret;
}




static void rtp_data_process(void)
{
	unsigned char cnt=5;
	unsigned char ret;
	do{
		ret= rtp_block_rec(rtp_net_handle.fd);
	}while(cnt-- && ret);
}


unsigned char led_visit_rtp_sta(void)
{
	unsigned char ret= 0;
	if(rtp_net_handle.fd != _FD_INVALID){
		unsigned int speed= rtp_net_handle.speed;
		if(speed > 1024) 
			ret=1;
	}
	return ret;
}


static void rtp_net_machine(void *parm)
{
	struct rsockt *h_net= (struct rsockt *)parm;
	if(h_net->isNeedCreat == 3){
		h_net->isNeedCreat = 0;
		_socket_close(&h_net->fd);
	}
	else if(h_net->isNeedCreat == 1){
		if(1 == rtp_creat_connect_socket(h_net)){
			h_net->isNeedCreat = 0;
		}
		else{
			h_net->isNeedCreat = 2;
			h_net->lastTimeSec = app_get_systime();
		}
	}
	else if(h_net->isNeedCreat == 2){
		if(h_net->lastTimeSec + 10*1000 < app_get_systime()){
			if(1 == rtp_creat_connect_socket(h_net)){
				h_net->isNeedCreat = 0;
			}
			else{
				h_net->lastTimeSec = app_get_systime();
			}
		}
	}
}

void rtp_net_start(unsigned int remote_ip, unsigned short remote_port)
{		
	struct rsockt *h_net= &rtp_net_handle;
	h_net->isNeedCreat = 1;
	h_net->ipaddr= remote_ip;
	h_net->port= remote_port;
}
void rtp_net_stop(void)
{
	struct rsockt *h_net= &rtp_net_handle;
	h_net->isNeedCreat = 3;
}

void rtp_net_restart(void)
{
	struct rsockt *h_net= &rtp_net_handle;
	if(h_net->fd != _FD_INVALID){
		_socket_close(&h_net->fd);
		h_net->isNeedCreat = 2;
		h_net->lastTimeSec = app_get_systime() + 2*1000;
	}
}


void rtp_test(void) {
extern void ebm_play_cmd_open(void);
extern void ebm_play_cmd_stop(void);
    static unsigned char cnt = 0;
    if((cnt++) == 100) {
        ebm_play_cmd_open();
    }

}


void rtp_net_loop(void)
{
	static volatile long rtp_cnt_timer;
#define CNT_TICK_SLEEP(n) app_sleep(&rtp_cnt_timer, n*1000)
#define CNT_TICK_PEND(n) app_pend_wake(rtp_cnt_timer)
#define RTP_TIME_OUT 20
	
	if(CNT_TICK_PEND()){
		rtp_net_machine(&rtp_net_handle);
		led_visit_rtp_sta();
		if(rtp_net_handle.fd != _FD_INVALID)
		{
			if(rtp_net_handle.speedCnt > 0)
				rtp_wcnt=0;
			else if(rtp_wcnt < RTP_TIME_OUT){
				if(rtp_wcnt == RTP_TIME_OUT-1)
				{
					printf("rtp pg time out, restart network\n");
					sys_log("节目接收超时停播");
					ebm_play_cmd_stop();
					command_net_restart();
					passback_net_restart();
					rtp_wcnt=0;
				}
				rtp_wcnt++;
			}
			rtp_net_handle.speed= rtp_net_handle.speedCnt/2;
			rtp_pack_loss=0;
			if(rtp_net_handle.speedCnt > 0)
				rtp_pack_loss= (rtp_pack_wcnt*100)/rtp_net_handle.speedCnt;
		}
		rtp_net_handle.speedCnt=0;
		rtp_pack_wcnt=0;
		CNT_TICK_SLEEP(2);
	}
	
	if(rtp_net_handle.fd != _FD_INVALID){
		rtp_data_process();
	}
	else
		usleep(10*1000);
}

unsigned char ebm_rtp_visit_netsta(unsigned int *current_ip, unsigned short *current_port)
{
	unsigned char ret=0;
	if(rtp_net_handle.fd != _FD_INVALID){
		ret=1;
		if(current_ip != NULL)
			*current_ip= rtp_net_handle.ipaddr;
		if(current_port != NULL)
			*current_port= rtp_net_handle.port;
	}
	return ret;
}



const char* visit_rtp_net_speed(void)
{
extern unsigned char visit_audio_fifo(void);

	static char buf[55];
	int idx=0;
	if(rtp_net_handle.fd == _FD_INVALID){
		sprintf(buf, "待机中");
	}
	else{
		unsigned int speed= rtp_net_handle.speed;
		idx= sprintf(buf, "已连接:");
		if(speed <= 1024)
			idx+= snprintf(&buf[idx], 55-idx, "%dB/s, 缓冲:%d%%", speed ,1 );
		else 
			idx+= snprintf(&buf[idx], 55-idx, "%dKB/s, 缓冲:%d%%", speed/1024 , 1 );
		//if(rtp_pack_loss > 0)
		snprintf(&buf[idx], 55-idx, "，丢包率:%d", rtp_pack_loss );
		
	}
	return buf;
}




